﻿using System;
using System.Linq;
using WiMo.Games.Premium.GDIDisplay.ImageAPI;
using System.Drawing;
using System.Collections.Generic;
using WiMo.Games.Drawables;
using System.Collections;

namespace WiMo.Games.Premium.GDIDisplay
{
    public class RenderTarget
    {
        public Rectangle BoundingRect { get; set; }
        public RenderTarget Parent { get; private set; }
        public RenderTarget NW { get; private set; }
        public RenderTarget NE { get; private set; }
        public RenderTarget SW { get; private set; }
        public RenderTarget SE { get; private set; }

        public RenderTarget Prev { get; set; }
        public RenderTarget Next { get; set; }
        public RenderTarget Above { get; set; }
        public RenderTarget Below { get; set; }

        private bool _isDirty;
        public bool IsDirty
        {
            get
            {                
                return _isDirty;
            }
            set
            {
                _isDirty = value;
            }
        }

        public List<IDrawable> Sprites { get; set; }

        public RenderTarget()
        {
            Sprites = new List<IDrawable>();
        }

        public void Remove(IDrawable sprite)
        {
            var targets = RenderTree.GetRenderTarget(sprite);
            foreach (var target in targets)
            {
                target.IsDirty = true;
                target.Sprites.Remove(sprite);
            }
        }

        public void AddSprite(IDrawable sprite)
        {
            if (BoundingRect.IntersectsWith(sprite.BoundingRect))
            {
                if (HasChildren)
                {
                    NW.AddSprite(sprite);
                    NE.AddSprite(sprite);
                    SW.AddSprite(sprite);
                    SE.AddSprite(sprite);
                }
                else
                {
                    Sprites.Add(sprite);
                    IsDirty = true;
                    RenderTree.GetRenderTarget(sprite).Add(this);
                }
            }
        }

        public void MarkAsClean()
        {
            IsDirty = false;

            if (HasChildren)
            {
                NW.MarkAsClean();
                NE.MarkAsClean();
                SW.MarkAsClean();
                SE.MarkAsClean();
            }
            else
                foreach (var sprite in Sprites)
                    sprite.IsDirty = false;
        }

        internal void ShowBlock(IWiMoGraphics graphics)
        {
            graphics.DrawRectangle(Color.White, Color.LightBlue, BoundingRect, 0x7f);
        }

        public void Render(IDisplay display)
        {
            var displayManager = display as DisplayManager;

            if(displayManager.BackgroundImage != null)
                displayManager.Graphics.DrawImage(displayManager.BackgroundImage.TextureInformation as Bitmap, (BoundingRect + displayManager.DisplayOffset), BoundingRect);
            else
            {
                displayManager.Graphics.FillRectangle(displayManager.BackgroundColor, (BoundingRect + displayManager.DisplayOffset));
            }

            var orderedSprites = Sprites.OrderBy(spr => spr.ZIndex);

            foreach (var sprite in orderedSprites.ToList())
            {
                var spriteImage = sprite as Drawables.SpriteImage;
                if (spriteImage != null)
                    spriteImage.Render(display, BoundingRect);

                var spriteText = sprite as Drawables.SpriteText;
                if(spriteText != null)
                    spriteText.Render(display, BoundingRect);

                var spriteRectangle = sprite as Drawables.Rectangle;
                if(spriteRectangle != null)
                    spriteRectangle.Render(displayManager, BoundingRect);
            }            
        }

        public RenderTarget(Rectangle rect)
        {
            BoundingRect = rect;
            Sprites = new List<IDrawable>();
        }

        public void CreateChildren()
        {
            NW = new RenderTarget(new Rectangle(BoundingRect.Left, BoundingRect.Top, BoundingRect.Width / 2, BoundingRect.Height / 2)) { Parent = this };
            NE = new RenderTarget(new Rectangle(NW.BoundingRect.Width + BoundingRect.Left, BoundingRect.Top, BoundingRect.Width / 2, BoundingRect.Height / 2)) { Parent = this };
            SW = new RenderTarget(new Rectangle(BoundingRect.Left, BoundingRect.Top + NE.BoundingRect.Height, BoundingRect.Width / 2, BoundingRect.Height / 2)) { Parent = this };
            SE = new RenderTarget(new Rectangle(NW.BoundingRect.Width + BoundingRect.Left, BoundingRect.Top + NW.BoundingRect.Height, BoundingRect.Width / 2, BoundingRect.Height / 2)) { Parent = this };
        }

        public bool HasChildren
        {
            get { return NW != null; }
        }

        public RenderTarget FindLastChild(Location point)
        {
            if (HasChildren)
            {
                if (NE.BoundingRect.Contains(point))
                    return NE.FindLastChild(point);

                if (NW.BoundingRect.Contains(point))
                    return NW.FindLastChild(point);

                if (SW.BoundingRect.Contains(point))
                    return SW.FindLastChild(point);

                if (SE.BoundingRect.Contains(point))
                    return SE.FindLastChild(point);
            }

            return this;
        }
    }
}
